package other.xsy.passlys.receivable;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rkhd.platform.sdk.api.annotations.RequestMethod;
import com.rkhd.platform.sdk.api.annotations.RestApi;
import com.rkhd.platform.sdk.api.annotations.RestBeanParam;
import com.rkhd.platform.sdk.api.annotations.RestMapping;
import com.rkhd.platform.sdk.data.model.*;
import com.rkhd.platform.sdk.exception.ApiEntityServiceException;
import com.rkhd.platform.sdk.log.Logger;
import com.rkhd.platform.sdk.log.LoggerFactory;
import com.rkhd.platform.sdk.service.XoqlService;
import org.apache.commons.lang.StringUtils;
import other.xsy.passlys.util.HCXObjectService;
import other.xsy.passlys.util.ResultVo;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 订单-应收模块服务类
 * @Author: 黎炎松
 * @Date: 2024/8/7 10:46
 */
@RestApi(baseUrl = "/pass/receivable")
public class ReceivableService {

    private static HCXObjectService hcxObjectService = new HCXObjectService();
    private static XoqlService xoqlService = XoqlService.instance();
    private static final Logger logger = LoggerFactory.getLogger();

    public static void main(String[] args) throws Exception {
        HCXObjectService.isLocal = true;
        ReceivableService receivableService = new ReceivableService();
        //receivableService.calcBookingAmount(3411642760583850L);


        // deBooking金额校验
        //String objStr = " {\"orderId\":3421530890508865,\"optPage\":1,\"deBookingDetailList\":[{\"amount__c\":2500,\"booking__c\":3421533296302685}],\"bankStatementId\":3413499296684621}";
        //ResultVo resultVo = receivableService.addUpDeBookingCheckAmount(JSONObject.parseObject(objStr));
        //System.out.println("resultVo = " + resultVo.getMsg());

        // 开票金额校验
        String objStr = "{\"invoiceDetailList\":[{\"invoiceDetails__c\":99907.37,\"receivablesDetail__c\":3617193549683369}],\"optPage\":1}";
        ResultVo resultVo = receivableService.addUpInvoiceDetailCheckAmount(JSONObject.parseObject(objStr));
        System.out.println("resultVo = " + resultVo.getMsg());

        //receivableService.calcAmounByBooking(Arrays.asList(3411642760583850L));

        // 认领金额校验
        //String objStr = "{\"optPage\":1,\"claimDetailList\":[{\"receivablesDetail__c\":3422058331478682,\"amountClaimed__c\":3000}],\"bankStatementId\":3421542527228505}";
        //ResultVo resultVo = receivableService.addUpClaimDetailCheckAmount(JSONObject.parseObject(objStr));
        //System.out.println("resultVo = " + resultVo.getMsg());

        // 计算认领金额
        //receivableService.calcClaimAmounByBooking(Arrays.asList(3411625768294999L));

        // 计算开票金额
        //receivableService.calcInvoiceAmounByBooking(Arrays.asList(3529220630157912L));

        //Claim__c claim__c = new Claim__c();
        //claim__c.setId(3423256744532657L);
        //Claim__c claim__c1 = hcxObjectService.get(claim__c);
        //System.out.println("claim__c1 = " + claim__c1);

        // 修改银行流水
        //receivableService.upBankStatementAmount(Arrays.asList(3411951189842502L));

        // 计算deBooking相关金额 {"isCalcOrderBookingAmount":"1","sceneType":1,"fromApproval":1,"deBookingId":3484183303150256}
        //JSONObject jsonObject = new JSONObject();
        //jsonObject.put("sceneType", 1);
        //jsonObject.put("fromApproval", 1);
        //jsonObject.put("deBookingId", 3484183303150256L);
        //jsonObject.put("isCalcOrderBookingAmount", "1");
        //receivableService.calcDeBookingAmount(jsonObject);
    }


    /**
     * 开票: 新增、编辑deBooking对金额进行校验（页面使用）
     * @return
     */
    @RestMapping(value = "/checkDeBookingAmount", method = RequestMethod.POST)
    public ResultVo addUpDeBookingCheckAmount(@RestBeanParam(name = "body") JSONObject jsonData) {
        String LOG_MSG = "新增、编辑deBooking对金额进行校验 ==> ";
        try {
            // 获取传入数据
            logger.info(LOG_MSG + "checkDeBookingAmount " + jsonData);
            Long orderId = jsonData.getLong("orderId"); // 订单id
            Long deBookingId = jsonData.getLong("deBookingId"); // debookingId
            Long bankStatementId = jsonData.getLong("bankStatementId"); // 银行流水id
            int optPage = jsonData.getInteger("optPage"); // 操作的页面 1: 新增编辑开票 2:新增编辑开票明细
            List<DebookingDetailed__c> deBookingDetailList = JSONArray.parseArray(jsonData.getString("deBookingDetailList"), DebookingDetailed__c.class);
            if (deBookingDetailList == null || deBookingDetailList.size() <= 0) {
                logger.error(LOG_MSG + "传入deBooking明细不可为空");
                return ResultVo.error("传入deBooking明细不可为空");
            }


            // 获取当前银行流水的deBooking占用总金额 （创建了的debooking就算占用）
            String sql = "select id,amount__c,booking__c,debooking__c.oaApprovalStatus__c oaApprovalStatus from debookingDetailed__c where debooking__c.YNrefund__c = 1 and debooking__c.runningWater__c = " + bankStatementId;
            if (deBookingId != null) {
                // 如果是编辑，排除掉当前的deBooking
                sql += " and debooking__c != " + deBookingId;
            }
            List<JSONObject> bankDebookingList = hcxObjectService.batchXoqlQuery(sql);


            // 首先判断deBooking的金额小于等于booking的可deBooking金额
            double amount = 0;
            String bookingIds = deBookingDetailList.stream().map(v -> v.getBooking__c().toString()).collect(Collectors.joining(","));
            sql = String.format("select id,contractAmountA__c,debookingAmount__c from booking__c where id in (%s)", bookingIds);
            List<Booking__c> bookingList = hcxObjectService.query(sql, Booking__c.class);
            for (int i = 0; i < deBookingDetailList.size(); i++) {
                DebookingDetailed__c debookingDetailed = deBookingDetailList.get(i);
                Double inputAmount = debookingDetailed.getAmount__c();
                amount = bgAdd(amount, inputAmount);

                // 获取booking的信息
                Long bookingId = debookingDetailed.getBooking__c();
                Booking__c booking = bookingList.stream().filter(v -> Objects.equals(v.getId(), bookingId)).findFirst().orElse(null);
                if (booking != null) {
                    double bookingAmount = bankDebookingList.stream().filter(v -> Objects.equals(v.getLong("booking__c"), bookingId)).map(v -> new BigDecimal(v.getDouble("amount__c"))).collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)).doubleValue();
                    double deBookingAmount = bgSub(booking.getContractAmountA__c(), bookingAmount); // 剩余可 deBooking的金额

                    if (inputAmount > deBookingAmount) {
                        String msg = String.format("第%s条明细,deBooking金额大于booking可用金额 (debooking金额为:%s,最大deBooking金额为:%s)", i + 1, inputAmount, deBookingAmount);
                        logger.error(LOG_MSG + msg);
                        return ResultVo.error(msg);
                    }
                }
            }

            // 获取银行流水数据：收款占用金额
            BankStatement__c bankStatement = new BankStatement__c();
            bankStatement.setId(bankStatementId);
            bankStatement = hcxObjectService.get(bankStatement);
            Double actualAmount = bankStatement.getActualAmount__c(); // 实际收款金额
            Double amountOccupied = bankStatement.getAmountOccupied__c(); // 收款占用金额
            // 当前银行流水在当前订单中指定booking认领的金额
            sql = String.format("select id,amountClaimed__c from claimDetails__c where claimStatusmx__c != 3 and claim__c.bankStatement__c = %s and orderNumber__c = %s and booking__c in (%s)", bankStatementId, orderId, bookingIds);
            List<JSONObject> claimDetailList = hcxObjectService.batchXoqlQuery(sql);
            double amountClaimed = claimDetailList.stream().map(v -> new BigDecimal(v.getString("amountClaimed__c"))).collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)).doubleValue();

            // 实际剩余deBooking金额 = ( 实际收款金额 - (收款占用金额 - 当前银行流水在当前订单中指定booking认领的金额) )- 已经被debooking的金额     因为审核通过后，会作废当前订单的认领
            double realAmountOccupied = bgSub(actualAmount, bgSub(amountOccupied, amountClaimed));

            // 当前银行流水审批不通过的deBooking占用总金额 （需要排除掉审批通过的，否则会进行重复扣减-审批通过的已赋值在银行流水的退款金额）
            double bookingAmount = bankDebookingList.stream().filter(v -> v.getInteger("oaApprovalStatus") != 5).map(v -> new BigDecimal(v.getDouble("amount__c"))).collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)).doubleValue();
            realAmountOccupied = bgSub(realAmountOccupied, bookingAmount); // 实际剩余deBooking金额
            logger.info(LOG_MSG + "amountClaimed:" + amountClaimed + " realAmountOccupied: " + realAmountOccupied);

            // 判断deBooking金额是否 大于 实际未占用金额
            if (amount > realAmountOccupied) {
                String msg = String.format("当前debooking总金额大于银行流水的实际剩余deBooking金额 (deBooking总金额为:%s, 实际剩余deBooking金额为: %s)", amount, realAmountOccupied);
                logger.error(LOG_MSG + msg);
                return ResultVo.error(msg);
            }

            logger.info(LOG_MSG + "金额校验通过");
            return ResultVo.success();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(LOG_MSG + "处理异常: " + e.getMessage());
            return ResultVo.error(e.getMessage());
        }
    }



    /**
     * 开票: 新增、编辑开票明细对开票金额进行校验（页面使用）
     * @return
     */
    @RestMapping(value = "/checkInvoiceDetailAmount", method = RequestMethod.POST)
    public ResultVo addUpInvoiceDetailCheckAmount(@RestBeanParam(name = "body") JSONObject jsonData) {
        String LOG_MSG = "新增、编辑开票明细对开票金额进行校验 ==> ";
        try {
            // 获取传入数据
            logger.info(LOG_MSG + "checkInvoiceDetailAmount " + jsonData);
            Long invoiceId = jsonData.getLong("invoiceId"); // 编辑时的开票id
            int optPage = jsonData.getInteger("optPage"); // 操作的页面 1: 新增编辑开票 2:新增编辑开票明细
            List<JSONObject> invoiceDetailData = JSONArray.parseArray(jsonData.getString("invoiceDetailList"), JSONObject.class);


            // 获取应收明细 amountReceivable__c: 应收明细金额
            String receivablesDetailIds = invoiceDetailData.stream().map(v -> v.getString("receivablesDetail__c")).collect(Collectors.joining(","));
            String sql = String.format("select id,name,amountReceivable__c from receivablesDetails__c where id in (%s)", receivablesDetailIds);
            List<ReceivablesDetails__c> receivablesDetailsList = hcxObjectService.query(sql, ReceivablesDetails__c.class);
            logger.info(LOG_MSG + "receivablesDetailsList " + receivablesDetailsList);

            // 获取当前应收明细已经存在的开票明细（新增时排查当前下的开票明细） invoiceDetails__c：开票明细金额  receivablesDetail__c: 应收明细
            sql = String.format("select id,invoiceDetails__c,receivablesDetail__c,billingStatus__c from invoiceDetail__c " +
                    " where invoice__c.customItem14__c != 3 and receivablesDetail__c in (%s)", receivablesDetailIds);
            if (invoiceId != null) {
                sql += " and invoice__c != " + invoiceId;
            }
            List<JSONObject> invoiceDetailList = hcxObjectService.batchXoqlQuery(sql);
            invoiceDetailList.addAll(invoiceDetailData);
            logger.info(LOG_MSG + "invoiceDetailList " + invoiceDetailList);

            // 按应收明细合并开票金额
            Map<Long, Double> amountMap = new HashMap<>();
            for (JSONObject invoiceDetail : invoiceDetailList) {

                Long receivablesDetailId = invoiceDetail.getLong("receivablesDetail__c");

                double amount = invoiceDetail.getDouble("invoiceDetails__c");
                if (amountMap.containsKey(receivablesDetailId)) {
                    Double clacAmount = amountMap.get(receivablesDetailId);
                    amountMap.put(receivablesDetailId, bgAdd(clacAmount, amount));
                } else {
                    amountMap.put(receivablesDetailId, amount);
                }

            }
            logger.info(LOG_MSG + "amountMap " + amountMap);

            // 进行比较，是否大于应收明细 (判断顺序使用传入参数)
            for (int i = 0; i < invoiceDetailData.size(); i++) {

                JSONObject invoiceDetail = invoiceDetailData.get(i);
                Long receivablesDetailId = invoiceDetail.getLong("receivablesDetail__c");

                // 获取应收明细信息
                ReceivablesDetails__c receivablesDetails = receivablesDetailsList.stream().filter(v -> Objects.equals(v.getId(), receivablesDetailId)).findFirst().orElse(null);
                if (receivablesDetails != null) {
                    Double amountReceivable = receivablesDetails.getAmountReceivable__c(); // 应收明细金额
                    Double invoiceAmount = amountMap.get(receivablesDetailId); // 总的开票金额
                    if (invoiceAmount > amountReceivable) {
                        // 获取最大的可填写开票明细金额 应收明细金额 -（总的开票金额 - 当前开票明细金额）
                        Double invoiceDetails = invoiceDetail.getDouble("invoiceDetails__c");
                        double maxAmount = bgSub(amountReceivable, bgSub(invoiceAmount, invoiceDetails));

                        // 区分提示语
                        String msg = "";
                        if (optPage == 1) {
                            msg = String.format("第%s条应收明细'%s': 总开票金额大于应收明细金额,最大可开票明细金额为%s (应收明细金额:%s,当前总开票金额:%s)", i + 1, receivablesDetails.getName(), maxAmount, amountReceivable, invoiceAmount);
                        } else {
                            msg = String.format("当前应收明细总开票金额大于应收明细金额,最大可开票明细金额为%s (应收明细金额:%s,当前总开票金额:%s)", maxAmount, amountReceivable, invoiceAmount);
                        }
                        logger.error(LOG_MSG + msg);
                        return ResultVo.error(msg);
                    }
                }
            }

            logger.info(LOG_MSG + "金额校验通过");
            return ResultVo.success();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(LOG_MSG + "处理异常: " + e.getMessage());
            return ResultVo.error(e.getMessage());
        }
    }

    /**
     * 认领: 新增、编辑认领明细对认领金额进行校验（页面使用）
     * @return
     */
    @RestMapping(value = "/checkClaimDetailAmount", method = RequestMethod.POST)
    public ResultVo addUpClaimDetailCheckAmount(@RestBeanParam(name = "body") JSONObject jsonData) {
        String LOG_MSG = "新增、编辑认领明细对认领金额进行校验 ==> ";
        try {
            // 获取传入数据
            logger.info(LOG_MSG + "checkClaimDetailAmount " + jsonData);
            Long claimId = jsonData.getLong("claimId"); // 编辑时的开票id
            int optPage = jsonData.getInteger("optPage"); // 操作的页面 1: 新增编辑开票 2:新增编辑认领明细
            List<ClaimDetails__c> claimDetailData = JSONArray.parseArray(jsonData.getString("claimDetailList"), ClaimDetails__c.class);


            // 获取应收明细 amountReceivable__c: 应收明细金额
            String receivablesDetailIds = claimDetailData.stream().map(v -> v.getReceivablesDetail__c().toString()).collect(Collectors.joining(","));
            String sql = String.format("select id,name,amountReceivable__c from receivablesDetails__c where id in (%s)", receivablesDetailIds);
            List<ReceivablesDetails__c> receivablesDetailsList = hcxObjectService.query(sql, ReceivablesDetails__c.class);
            logger.info(LOG_MSG + "receivablesDetailsList " + receivablesDetailsList);


            // 获取当前应收明细已经存在的认领明细（编辑时排除当前下的认领明细） amountClaimed__c：认领金额  receivablesDetail__c: 应收明细
            sql = String.format("select id,amountClaimed__c,receivablesDetail__c from claimDetails__c " +
                    " where claimStatusmx__c != 3 and receivablesDetail__c in (%s)", receivablesDetailIds);
            if (claimId != null) {
                sql += " and claim__c != " + claimId;
            }
            List<ClaimDetails__c> claimDetailList = hcxObjectService.query(sql, ClaimDetails__c.class);
            if (claimDetailList == null) {
                claimDetailList = new ArrayList<>();
            }
            claimDetailList.addAll(claimDetailData);
            logger.info(LOG_MSG + "claimDetailList " + claimDetailList);

            // 按应收明细合并认领金额
            Map<Long, Double> amountMap = new HashMap<>();
            double totalAmount = 0;
            for (ClaimDetails__c claimDetail : claimDetailList) {
                Long receivablesDetailId = claimDetail.getReceivablesDetail__c();

                double amount = claimDetail.getAmountClaimed__c();

                // 汇总当前传入的应收金额
                if (claimDetail.getId() == null) {
                    totalAmount = bgAdd(totalAmount, amount);
                }

                if (amountMap.containsKey(receivablesDetailId)) {
                    Double clacAmount = amountMap.get(receivablesDetailId);
                    amountMap.put(receivablesDetailId, bgAdd(clacAmount, amount));
                } else {
                    amountMap.put(receivablesDetailId, amount);
                }

            }
            logger.info(LOG_MSG + "amountMap " + amountMap);


            // 进行比较，是否大于应收明细 (判断顺序使用传入参数)
            for (int i = 0; i < claimDetailData.size(); i++) {

                ClaimDetails__c claimDetail = claimDetailData.get(i);
                Long receivablesDetailId = claimDetail.getReceivablesDetail__c();

                // 获取应收明细信息
                ReceivablesDetails__c receivablesDetails = receivablesDetailsList.stream().filter(v -> Objects.equals(v.getId(), receivablesDetailId)).findFirst().orElse(null);
                if (receivablesDetails != null) {
                    Double amountReceivable = receivablesDetails.getAmountReceivable__c(); // 应收明细金额
                    Double claimAmount = amountMap.get(receivablesDetailId); // 总的认领金额
                    if (claimAmount > amountReceivable) {
                        // 获取最大的可填写认领明细金额 应收明细金额 -（总的认领金额 - 当前认领明细金额）
                        Double amountClaimed = claimDetail.getAmountClaimed__c();
                        Double maxAmount = bgSub(amountReceivable, bgSub(claimAmount, amountClaimed));

                        // 区分提示语
                        String msg = "";
                        if (optPage == 1) {
                            msg = String.format("第%s条应收明细'%s': 总认领金额大于应收明细金额,最大可认领明细金额为%s (应收明细金额:%s,当前总认领金额:%s)", i + 1, receivablesDetails.getName(), maxAmount, amountReceivable, claimAmount);
                        } else {
                            msg = String.format("当前应收明细总认领金额大于应收明细金额,最大可认领明细金额为%s (应收明细金额:%s,当前总认领金额:%s)", maxAmount, amountReceivable, claimAmount);
                        }
                        logger.error(LOG_MSG + msg);
                        return ResultVo.error(msg);
                    }
                }
            }


            // 银行流水金额判断： 获取当前 收款（银行流水） 实际收款金额 (actualAmount__c)、其它认领明细中已经认领的金额
            Long bankStatementId = jsonData.getLong("bankStatementId"); // 银行明细id
            if (optPage == 2) {
                // 单个认领流水 根据认领获取银行流水id
                sql = "select id,bankStatement__c from claim__c where id = " + claimId;
                Claim__c claim = hcxObjectService.queryOne(sql, Claim__c.class);
                bankStatementId = claim.getBankStatement__c();
            }
            BankStatement__c bankStatement = new BankStatement__c();
            bankStatement.setId(bankStatementId);
            bankStatement = hcxObjectService.get(bankStatement);
            Double actualAmount = bankStatement.getActualAmount__c();
            sql = "select id,amountClaimed__c from claimDetails__c where claimStatusmx__c != 3 and claim__c.bankStatement__c = " + bankStatementId;
            if (claimId != null) {
                sql += " and claim__c != " + claimId;
            }
            List<JSONObject> bankClaimDetailList = hcxObjectService.batchXoqlQuery(sql);
            double bankAmountClaimed = bankClaimDetailList.stream().map(v -> new BigDecimal(v.getString("amountClaimed__c"))).collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)).doubleValue();
            // 判断当前银行流水金额是否已经被认领完
            double sumAmountClaimed = bgAdd(bankAmountClaimed, totalAmount);
            if (sumAmountClaimed > actualAmount) {
                double calcAmount = bgSub(actualAmount, bankAmountClaimed);
                String msg = String.format("当前银行流水总认领金额大于银行流水剩余收款金额，银行流水剩余最大可认领金额为%s (银行流水实际收款金额:%s,当前银行流水总认领金额:%s)", calcAmount, actualAmount, sumAmountClaimed);
                if (calcAmount < 0) {
                    msg = String.format("当前银行流水金额已被认领，认领金额超%s,请检查当前银行流水关联的应收明细！", -calcAmount);
                }
                logger.error(LOG_MSG + msg);
                return ResultVo.error(msg);
            }

            logger.info(LOG_MSG + "金额校验通过");
            return ResultVo.success();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(LOG_MSG + "处理异常: " + e.getMessage());
            return ResultVo.error(e.getMessage());
        }
    }


    /**
     * 开票模块: 重置Booking下关联的开票金额字段
     * @param bookingIdList
     * @return
     */
    public ResultVo calcInvoiceAmounByBooking(List<Long> bookingIdList) {
        String LOGGER_MSG = "重置Booking下关联的开票金额字段 ==> bookingIdList = " + bookingIdList;
        try {
            if (bookingIdList == null || bookingIdList.size() <= 0) {
                logger.error(LOGGER_MSG + "传入参数为空");
                return ResultVo.error("传入参数为空");
            }
            String bookingIds = StringUtils.join(bookingIdList, ",");

            // 获取当前Booking下的所有开票数据，然后计算Booking、应收相关金额字段进行更新
            String sql = String.format("select id,booking__c,invoiceDetails__c,receivablesDetail__c,invoice__c.approvalStatus approvalStatus,billingStatus__c " +
                    " from invoiceDetail__c where booking__c in (%s)", bookingIds);
            List<JSONObject> originInvoiceDetailList = hcxObjectService.batchXoqlQuery(sql);
            logger.debug(LOGGER_MSG + " originInvoiceDetailList " + originInvoiceDetailList.size());
            if (originInvoiceDetailList == null || originInvoiceDetailList.size() <= 0) {
                logger.error(LOGGER_MSG + "无需要处理的开票明细数据");
                //return ResultVo.success("无需要处理的开票明细数据");
            }

            // 获取非作废的数据
            List<JSONObject> invoiceDetailList = originInvoiceDetailList.stream().filter(v -> v.getInteger("billingStatus__c") == null || v.getInteger("billingStatus__c") != 3).collect(Collectors.toList());

            // 设置Booking 金额字段
            sql = String.format("select id,BinvoicedAmount__c from booking__c where id in (%s)", bookingIds);
            List<Booking__c> bookingList = hcxObjectService.query(sql, Booking__c.class);
            List<Booking__c> upBookingList = new ArrayList<>();
            for (Booking__c booking : bookingList) {

                // 已开票金额 获取审批通过的开票数据
                double binvoicedAmount = invoiceDetailList.stream().filter(v -> Objects.equals(v.getLong("booking__c"), booking.getId()) && v.getInteger("approvalStatus") == 3)
                        .mapToDouble(v -> v.getDouble("invoiceDetails__c")).sum();
                // 不同进行修改
                if (!Objects.equals(binvoicedAmount, booking.getBinvoicedAmount__c())) {
                    booking.setBinvoicedAmount__c(binvoicedAmount);
                    upBookingList.add(booking);
                }
            }
            // 进行修改
            logger.debug(LOGGER_MSG + " upBookingList " + upBookingList);
            if (upBookingList.size() > 0) {
                Boolean update = hcxObjectService.batchUpdate(upBookingList);
                if (!update) {
                    logger.error(LOGGER_MSG + "修改booking金额字段异常");
                    //return ResultVo.error("修改booking金额字段异常");
                }
            }

            // 设置应收 已开票、开票占用字段
            //String receivablesIds = originInvoiceDetailList.stream().map(v -> v.getString("receivablesDetail__c")).distinct().collect(Collectors.joining(","));
            //// 如果应收id为空，则查询booking下的应收（删除开票主表的情况,重置应收明细的金额）
            //if (StringUtils.isBlank(receivablesIds)) {
            //    sql = String.format("select id from receivablesDetails__c where booking__c in (%s)", bookingIds);
            //} else {
            //    sql = String.format("select id from receivablesDetails__c where id in (%s)", receivablesIds);
            //}

            sql = String.format("select id from receivablesDetails__c where booking__c in (%s)", bookingIds);
            List<ReceivablesDetails__c> receivablesDetailsList = hcxObjectService.query(sql, ReceivablesDetails__c.class);
            List<ReceivablesDetails__c> upReceivablesDetailsList = new ArrayList<>();
            for (ReceivablesDetails__c receivablesDetails : receivablesDetailsList) {

                List<JSONObject> tempList = invoiceDetailList.stream().filter(v -> Objects.equals(v.getLong("receivablesDetail__c"), receivablesDetails.getId())).collect(Collectors.toList());

                // 已开票金额 invoicedAmount__c  只获取审批通过的
                double binvoicedAmount = tempList.stream().filter(v -> v.getInteger("approvalStatus") == 3).mapToDouble(v -> v.getDouble("invoiceDetails__c")).sum();
                receivablesDetails.setInvoicedAmount__c(binvoicedAmount);

                // 开票占用金额 invoicingAmount__c
                double invoicingAmount = tempList.stream().mapToDouble(v -> v.getDouble("invoiceDetails__c")).sum();
                receivablesDetails.setInvoicingAmount__c(invoicingAmount);

                upReceivablesDetailsList.add(receivablesDetails);
            }
            logger.debug(LOGGER_MSG + " upReceivablesDetailsList " + upReceivablesDetailsList);
            Boolean update = hcxObjectService.batchUpdate(upReceivablesDetailsList);
            if (!update) {
                logger.error(LOGGER_MSG + "修改应收金额字段异常");
                //return ResultVo.error("修改应收金额字段异常");
            }

            logger.debug(LOGGER_MSG + "处理成功");
            return ResultVo.success();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(LOGGER_MSG + "处理异常:" + e.getMessage());
            return ResultVo.error("处理异常:" + e.getMessage());
        }
    }


    /**
     * 认领模块: 重置Booking下关联的认领金额字段
     * @param bookingIdList
     * @return
     */
    public ResultVo calcClaimAmounByBooking(List<Long> bookingIdList) {
        String LOGGER_MSG = "重置Booking下关联的认领金额字段 ==> ";
        try {
            if (bookingIdList == null || bookingIdList.size() <= 0) {
                logger.error(LOGGER_MSG + "传入参数为空");
                return ResultVo.error("传入参数为空");
            }
            String bookingIds = StringUtils.join(bookingIdList, ",");

            // 获取当前Booking下的所有认领数据，然后计算Booking、应收相关金额字段进行更新
            String sql = String.format("select id,booking__c,amountClaimed__c,receivablesDetail__c,claim__c.approvalStatus approvalStatus,claim__c.bankStatement__c bankStatement,claimStatusmx__c " +
                    " from claimDetails__c where booking__c in (%s)", bookingIds);
            List<JSONObject> originClaimDetailList = hcxObjectService.batchXoqlQuery(sql);
            logger.debug(LOGGER_MSG + " originClaimDetailList " + originClaimDetailList.size());
            if (originClaimDetailList == null || originClaimDetailList.size() <= 0) {
                logger.error(LOGGER_MSG + "无需要处理的认领明细数据");
                //return ResultVo.success("无需要处理的认领明细数据");
            }

            // 获取非作废的
            List<JSONObject> claimDetailList = originClaimDetailList.stream().filter(v -> v.getInteger("claimStatusmx__c") == null || v.getInteger("claimStatusmx__c") != 3).collect(Collectors.toList());


            // 设置Booking 金额字段
            sql = String.format("select id,acceptedMoney__c from booking__c where id in (%s)", bookingIds);
            List<Booking__c> bookingList = hcxObjectService.query(sql, Booking__c.class);
            List<Booking__c> upBookingList = new ArrayList<>();
            for (Booking__c booking : bookingList) {

                // 已认款金额 获取审批通过的应收数据
                double amountClaimed = claimDetailList.stream().filter(v -> Objects.equals(v.getLong("booking__c"), booking.getId()) && v.getInteger("approvalStatus") == 3)
                        .mapToDouble(v -> v.getDouble("amountClaimed__c")).sum();
                // 不同进行修改
                if (!Objects.equals(amountClaimed, booking.getAcceptedMoney__c())) {
                    booking.setAcceptedMoney__c(amountClaimed);
                    upBookingList.add(booking);
                }
            }
            // 进行修改
            logger.debug(LOGGER_MSG + " upBookingList " + upBookingList);
            if (upBookingList.size() > 0) {
                Boolean update = hcxObjectService.batchUpdate(upBookingList);
                if (!update) {
                    logger.error(LOGGER_MSG + "修改booking金额字段异常");
                    //return ResultVo.error("修改booking金额字段异常");
                }
            }

            // 设置应收 已认领、认领占用字段
            //String receivablesIds = originClaimDetailList.stream().map(v -> v.getString("receivablesDetail__c")).distinct().collect(Collectors.joining(","));
            //// 如果应收id为空，则查询booking下的应收（删除认领主表的情况,重置应收明细的金额）
            //if (StringUtils.isBlank(receivablesIds)) {
            //    sql = String.format("select id from receivablesDetails__c where booking__c in (%s)", bookingIds);
            //} else {
            //    sql = String.format("select id from receivablesDetails__c where id in (%s)", receivablesIds);
            //}

            sql = String.format("select id from receivablesDetails__c where booking__c in (%s)", bookingIds);
            List<ReceivablesDetails__c> receivablesDetailsList = hcxObjectService.query(sql, ReceivablesDetails__c.class);
            List<ReceivablesDetails__c> upReceivablesDetailsList = new ArrayList<>();
            for (ReceivablesDetails__c receivablesDetails : receivablesDetailsList) {

                List<JSONObject> tempList = claimDetailList.stream().filter(v -> Objects.equals(v.getLong("receivablesDetail__c"), receivablesDetails.getId())).collect(Collectors.toList());

                // 已认款金额 acceptedMoney__c  只获取审批通过的
                double acceptedMoney = tempList.stream().filter(v -> v.getInteger("approvalStatus") == 3).mapToDouble(v -> v.getDouble("amountClaimed__c")).sum();
                receivablesDetails.setAcceptedMoney__c(acceptedMoney);

                // 认领占用金额 claimOccupation__c
                double claimOccupation = tempList.stream().mapToDouble(v -> v.getDouble("amountClaimed__c")).sum();
                receivablesDetails.setClaimOccupation__c(claimOccupation);

                upReceivablesDetailsList.add(receivablesDetails);
            }
            logger.debug(LOGGER_MSG + " upReceivablesDetailsList " + upReceivablesDetailsList);
            Boolean update = hcxObjectService.batchUpdate(upReceivablesDetailsList);
            if (!update) {
                logger.error(LOGGER_MSG + "修改应收金额字段异常");
                //return ResultVo.error("修改应收金额字段异常");
            }

            // 设置银行流水 已认领金额、占用金额,需要根据银行流水获取当前银行流水下的认领明细
            List<Long> bankStatementIdList = originClaimDetailList.stream().map(v -> v.getLong("bankStatement")).distinct().collect(Collectors.toList());
            upBankStatementAmount(bankStatementIdList);


            logger.debug(LOGGER_MSG + "处理成功");
            return ResultVo.success();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(LOGGER_MSG + "处理异常:" + e.getMessage());
            return ResultVo.error("处理异常:" + e.getMessage());
        }
    }

    /**
     * 根据银行流水id更新银行流水的应收
     * @param bankStatementIdList
     */
    public void upBankStatementAmount(List<Long> bankStatementIdList) throws Exception {
        if (bankStatementIdList == null || bankStatementIdList.size() <= 0) {
            logger.debug("更新银行流水 bankStatementIdList 为空");
            return;
        }

        String sql = String.format("select id,booking__c,amountClaimed__c,receivablesDetail__c,claim__c.approvalStatus approvalStatus,claim__c.bankStatement__c bankStatement " +
                " from claimDetails__c where claimStatusmx__c != 3 and claim__c.bankStatement__c in (%s)", StringUtils.join(bankStatementIdList, ","));
        List<JSONObject> bankClaimDetailList = hcxObjectService.batchXoqlQuery(sql);
        List<BankStatement__c> upBankStatementList = new ArrayList<>();
        for (Long bankStatementId : bankStatementIdList) {
            BankStatement__c bankStatement = new BankStatement__c();
            bankStatement.setId(bankStatementId);

            List<JSONObject> tempList = bankClaimDetailList.stream().filter(v -> Objects.equals(v.getLong("bankStatement"), bankStatementId)).collect(Collectors.toList());

            // 已认领金额 amountClaimed__c  只获取审批通过的
            double amountClaimed = tempList.stream().filter(v -> v.getInteger("approvalStatus") == 3).mapToDouble(v -> v.getDouble("amountClaimed__c")).sum();
            bankStatement.setAmountClaimed__c(amountClaimed);

            // 收款占用金额 amountOccupied__c
            double amountOccupied = tempList.stream().mapToDouble(v -> v.getDouble("amountClaimed__c")).sum();
            bankStatement.setAmountOccupied__c(amountOccupied);

            upBankStatementList.add(bankStatement);
        }
        logger.debug("更新银行流水 upBankStatementList " + upBankStatementList);
        boolean update = hcxObjectService.batchUpdate(upBankStatementList);
        if (!update) {
            logger.error("更新银行流水金额字段异常");
            //return ResultVo.error("修改银行流水金额字段异常");
        }
    }


    /**
     * 计算deBooking相关金额
     * @param jsonData
     * @param
     * @return
     */
    @RestMapping(value = "/calcDeBookingAmount", method = RequestMethod.POST)
    public ResultVo calcDeBookingAmount(@RestBeanParam(name = "body") JSONObject jsonData) {
        String LOGGER_MSG = "重置deBooking下关联的金额字段 ==> ";
        try {
            // 公共参数
            logger.info(LOGGER_MSG + "jsonData: " + jsonData);
            Integer sceneType = jsonData.getInteger("sceneType"); // 场景的类型 1: deBooking审批通过,只需要入参deBookingId 即可  2:删除deBooking，需要入参deBookign以及明细的数据 （删除后查不到明细数据）
            Long deBookingId = jsonData.getLong("deBookingId");
            Debooking__c debooking = new Debooking__c();
            String bookingIds = "";
            List<Long> bookingIdList = null;
            if (sceneType == 2) {
                // 删除deBooking，进行赋值
                bookingIds = jsonData.getString("bookingStr");
                bookingIdList = Arrays.stream(bookingIds.split(",")).map(v -> Long.valueOf(v)).distinct().collect(Collectors.toList());
                debooking.setYNrefund__c(jsonData.getInteger("YNrefund"));
                debooking.setRunningWater__c(jsonData.getLong("runningWater"));
            } else {
                // 审批通过
                debooking.setId(deBookingId);
                debooking = hcxObjectService.get(debooking);
                logger.info(LOGGER_MSG + "处理开始: " + debooking);

                // 获取deBooking明细
                String sql = "select id,booking__c from debookingDetailed__c where debooking__c = " + deBookingId;
                List<DebookingDetailed__c> debookingDetailList = hcxObjectService.query(sql, DebookingDetailed__c.class);
                bookingIdList = debookingDetailList.stream().map(v -> v.getBooking__c()).distinct().collect(Collectors.toList());
                bookingIds = StringUtils.join(bookingIdList, ",");
            }
            logger.info(LOGGER_MSG + "bookingIdList: " + bookingIdList);


            // 更新booking对象的debooking字段金额
            String sql = String.format("select id,amount__c,booking__c from debookingDetailed__c where debooking__c.oaApprovalStatus__c = 5 and booking__c in (%s)", bookingIds);
            List<JSONObject> tempdebookingDetailList = hcxObjectService.batchXoqlQuery(sql);
            logger.info(LOGGER_MSG + "tempdebookingDetailList: " + tempdebookingDetailList);
            List<Booking__c> upBookingList = new ArrayList<>();
            for (Long bookingId : bookingIdList) {
                Booking__c booking = new Booking__c();
                booking.setId(bookingId);

                double deBookingAmount = tempdebookingDetailList.stream().filter(v -> Objects.equals(v.getLong("booking__c"), bookingId)).map(v -> new BigDecimal(v.getString("amount__c"))).collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)).doubleValue();
                booking.setDebookingAmount__c(deBookingAmount);

                upBookingList.add(booking);
            }
            Boolean update = hcxObjectService.batchUpdate(upBookingList);
            logger.info(LOGGER_MSG + "批量修改booking:" + update);


            // 更新银行流水的退款金额
            Long bankId = debooking.getRunningWater__c();
            if (debooking.getYNrefund__c() == 1 && bankId != null) {
                sql = String.format("select id,amount__c,booking__c from debookingDetailed__c where debooking__c.oaApprovalStatus__c = 5 and debooking__c.runningWater__c = %s", bankId);
                tempdebookingDetailList = hcxObjectService.batchXoqlQuery(sql);

                double deBookingAmount = tempdebookingDetailList.stream().map(v -> new BigDecimal(v.getString("amount__c"))).collect(Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)).doubleValue();

                BankStatement__c bankStatement = new BankStatement__c();
                bankStatement.setId(bankId);
                bankStatement.setAmountRefunded__c(deBookingAmount);
                update = hcxObjectService.update(bankStatement);
                logger.info(LOGGER_MSG + "修改银行流水已退款金额:" + update + " deBookingAmount: " + deBookingAmount);
            }


            // 删除deBooking 不需要作废认领明细
            if (sceneType == 1) {
                // 作废关联booking下的认领明细 bookingIdList
                sql = String.format("select id from claimDetails__c where booking__c in (%s)", bookingIds);
                List<ClaimDetails__c> claimDetailList = hcxObjectService.query(sql, ClaimDetails__c.class);
                if (claimDetailList != null && claimDetailList.size() > 0) {
                    List<ClaimDetails__c> upClaimDetailList = new ArrayList<>();
                    for (ClaimDetails__c claimDetails : claimDetailList) {
                        claimDetails.setClaimStatusmx__c(3);
                        upClaimDetailList.add(claimDetails);
                    }
                    update = hcxObjectService.batchUpdate(upClaimDetailList);
                    logger.info(LOGGER_MSG + "批量修改认领明细:" + update);
                }

                // 修改开票、认领金额字段
                calcInvoiceAmounByBooking(bookingIdList);
                calcClaimAmounByBooking(bookingIdList);
            }


            // 是否重新计算订单上的booking金额 (本地模拟OA审批完成后需要重新计算金额)
            String isCalcOrderBookingAmount = jsonData.getString("isCalcOrderBookingAmount");
            if (isCalcOrderBookingAmount != null) {
                new CalcOrderBookingAmount().dealOrderBookingAmount(debooking.getOrder__c());
            }

            logger.info(LOGGER_MSG + "处理成功");
            return ResultVo.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVo.error("处理异常: "  + e.getMessage());
        }
    }


    /**
     * 加
     * @param v1
     * @param v2
     * @return
     */
    public double bgAdd(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 减
     * @param v1
     * @param v2
     * @return
     */
    public double bgSub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }


}
